JavaScript 事件模型系列(四)jQuery 中的事件模型

前言

jQuery中提供了四种事件绑定方式,分别是bind、live、delegate、on,对应的解除监听的函数分别是unbind、die、undelegate、off。

先声明一个例子,各函数的用法将围绕这个例子。

1
2
3
4
5
6
7
8
9
10
11
12
13
<ul id="uList">
<li id="list1" class="item">列表元素1</li>
<li id="list1" class="item">列表元素2</li>
<li id="list1" class="item">列表元素3</li>
<li id="list1" class="item">列表元素4</li>
<li id="list1" class="item">列表元素5</li>
</ul>
<script type="text/javascript">
function getText() {
console.log(this.innerHTML);
}
</script>

原理

on

1
$(element).on(type,[selector],[data],fn);
  • type:事件类型(不带 on,打引号)

  • selector:可选,触发事件的元素,若没有设置则默认为 element

  • data:可选,返回绑定当前事件处理程序时,传递的附加数据,通过 event.data 调用

  • fn:事件处理程序,可传入事件对象

data 参数的使用:

1
2
3
4
5
6
7
// 附加数据可以为任意类型
var userObj = { name: "Echo", age: 18 };
// 为所有p元素绑定click事件,并传入附加数据(user)
$("p").on( "click", userObj, function(event){
console.log(event.data.name); // Echo
} );

我们看到前有调用 on 的元素 element,后有函数参数 selector,那么二者之间的关系是什么呢,我们先不设置 selector,那么事件处理程序和事件都会默认绑定在 element 上。

1
$("#uList").on("click",getText);

on方法不带selector

再将 selector 设置为 li 时,

1
2
3
$("#uList").on("click","li",getText);
// 点击列表元素 1
// 列表元素1

这样看,还有点事件委托的意味,调用该方法的元素 element 绑定了事件处理程序,而参数中的 selector 才是触发事件的元素。

bind

1
$(element).bind(type,[data],fn);
  • type:事件类型(不带 on,打引号)

  • data:可选,返回绑定当前事件处理程序时,传递的附加数据,通过 event.data 调用

  • fn:事件处理程序,可传入事件对象

在最开始学 jQuery 的时候,用的最多的就是 bind 方法。来看 bind 的源码:

1
2
3
function (types, data, fn) {
return this.on (types, null, data, fn);
}

可以看到 bind 是调用了 on 方法,并设置 selector 属性为 null。

1
$("#uList").bind("click",getText);

bind方法

1
2
3
$("#list1").bind("click",getText);
// 点击列表元素 1
// 列表元素1

live

1
$(element).live(type,[data],fn);
  • type:事件类型(不带 on,打引号)

  • data:可选,返回绑定当前事件处理程序时,传递的附加数据,通过 event.data 调用

  • fn:事件处理程序,可传入事件对象

live 源码:

1
2
3
4
function (types, data, fn) {
jQuery (this.context).on(types, this.selector, data, fn);
return this;
}

live 方法其实也是调用了 on 方法,但不是绑定到调用的元素上,而是绑定到 this.context,那 context 又是什么呢,我个人认为就是该元素的上下文,在可以使用 live 方法的 jQuery 版本下:

1
2
$("#uList").context; // #document
"#list1").context; // #document

而在 jQuery1.7 以上版本:

1
2
$("#uList").context; // undefined
$("#list1").context; // undefined

因此这就导致了一个弊端,将所有事件都委托到根节点上,根节点负担太大,并且在 DOM 节点较为复杂时会有意料之外的结果,所以 jQuery1.7 之后就废弃了 live 方法。

1
$("#uList").live("click",getText);

live

1
2
3
$("#list1").on("click",getText);
// 点击列表元素 1
// 列表元素1

delegate

1
$(element).delegate(selector,type,[data],fn);
  • selector:触发事件的元素

  • type:事件类型(不带 on,打引号)

  • data:可选,返回绑定当前事件处理程序时,传递的附加数据,通过 event.data 调用

  • fn:事件处理程序,可传入事件对象

对于一下 on 方法:

1
$(element).on(type,[selector],[data],fn);

再看 delegate 的源码:

1
2
3
function(selector, types, data, fn) {
return this.on( types, selector, data, fn );
}

与 on 方法的唯一区别就是不能省略 selector 参数,其实从这个函数名就可以看的出来:delegate(委托),调用 delegate 方法的 element 就是被委托的元素,绑定了事件处理程序,而 selector 是触发事件的元素。

1
2
3
$("#uList").delegate("li","click",getText);
// 点击列表元素 1
// 列表元素1

比较

官方推荐尽量使用 on 方法,其他三种方法也是调用了 on 方法。

bind 方法:优点是清晰,直接,适合于将事件和事件处理程序直接绑定在单独的元素上,而缺点就是,不能将事件处理程序绑定到页面上的其他元素(也就是不能进行事件代理)。

live 方法:已经被弃用了就不多说了,将所有事件都委托到根节点上,根节点负担太大,并且在 DOM 节点较为复杂时会有意料之外的结果。

delegate 方法:相比于 live 方法而言,可以指定代理元素,速度比 live 方法要快,但相比与 bind 方法,还是要慢的,因为要冒泡到代理元素上再执行事件处理程序。

Fork me on GitHub